package com.javaxiaobear.base.framework.config;

import cn.hutool.core.util.ObjectUtil;
import com.javaxiaobear.base.common.utils.spring.SpringUtils;
import com.javaxiaobear.base.framework.redisson.ForyCodec;
import com.javaxiaobear.base.framework.redisson.KeyPrefixHandler;
import lombok.extern.slf4j.Slf4j;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.codec.CompositeCodec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.codec.Kryo5Codec;
import org.redisson.codec.LZ4Codec;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.VirtualThreadTaskExecutor;

/** redis配置 */
@Slf4j
@Configuration
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfig {

  private Codec getCodec(RedissonProperties.CodecType codecType) {
    return switch (codecType) {
      case JSON -> new JsonJacksonCodec();
      case Kryo -> new Kryo5Codec();
      case String -> StringCodec.INSTANCE;
      case Fory -> ForyCodec.INSTANCE;
      case null -> throw new UnsupportedOperationException("不支持的序列化方式");
    };
  }

  @Bean
  public RedissonAutoConfigurationCustomizer redissonCustomizer(
      RedissonProperties redissonProperties) {
    return config -> {
      // 组合序列化 key 使用 String 内容使用通用 json 格式
      CompositeCodec codec;
      if (redissonProperties.isCompress()) {
        codec =
            new CompositeCodec(
                StringCodec.INSTANCE,
                new LZ4Codec(getCodec(redissonProperties.getCodec())),
                new LZ4Codec(getCodec(redissonProperties.getCodec())));
      } else {
        codec =
            new CompositeCodec(
                StringCodec.INSTANCE,
                getCodec(redissonProperties.getCodec()),
                getCodec(redissonProperties.getCodec()));
      }

      config
          .setThreads(redissonProperties.getThreads())
          .setNettyThreads(redissonProperties.getNettyThreads())
          // 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现)
          .setUseScriptCache(true)
          .setCodec(codec);
      if (SpringUtils.isVirtual()) {
        log.info("redisson使用虚拟线程池");
        config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-"));
      }
      RedissonProperties.SingleServerConfig singleServerConfig =
          redissonProperties.getSingleServerConfig();
      if (ObjectUtil.isNotNull(singleServerConfig)) {
        // 使用单机模式
        config
            .useSingleServer()
            // 设置redis key前缀
            .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
            .setTimeout(singleServerConfig.getTimeout())
            .setClientName(singleServerConfig.getClientName())
            .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
            .setSubscriptionConnectionPoolSize(
                singleServerConfig.getSubscriptionConnectionPoolSize())
            .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
            .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize());
      }
      // 集群配置方式 参考下方注释
      RedissonProperties.ClusterServersConfig clusterServersConfig =
          redissonProperties.getClusterServersConfig();
      if (ObjectUtil.isNotNull(clusterServersConfig)) {
        config
            .useClusterServers()
            // 设置redis key前缀
            .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
            .setTimeout(clusterServersConfig.getTimeout())
            .setClientName(clusterServersConfig.getClientName())
            .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
            .setSubscriptionConnectionPoolSize(
                clusterServersConfig.getSubscriptionConnectionPoolSize())
            .setMasterConnectionMinimumIdleSize(
                clusterServersConfig.getMasterConnectionMinimumIdleSize())
            .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
            .setSlaveConnectionMinimumIdleSize(
                clusterServersConfig.getSlaveConnectionMinimumIdleSize())
            .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
            .setReadMode(clusterServersConfig.getReadMode())
            .setSubscriptionMode(clusterServersConfig.getSubscriptionMode());
      }
      log.info("初始化 redis 配置");
    };
  }
}
